/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.zbbt.sportslottery.ui.widget.swipe;

import com.zbbt.sportslottery.ui.adapter.HomeRecyclerAdapter.OnBottomClickListener;
import com.zbbt.sportslottery.util.LogUtil;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;
import android.widget.AbsListView;

/**
 * The SwipeRefreshLayout should be used whenever the user can refresh the
 * contents of a view via a vertical swipe gesture. The activity that
 * instantiates this view should add an OnRefreshListener to be notified
 * whenever the swipe to refresh gesture is completed. The SwipeRefreshLayout
 * will notify the listener each and every time the gesture is completed again;
 * the listener is responsible for correctly determining when to actually
 * initiate a refresh of its content. If the listener determines there should
 * not be a refresh, it must call setRefreshing(false) to cancel any visual
 * indication of a refresh. If an activity wishes to show just the progress
 * animation, it should call setRefreshing(true). To disable the gesture and
 * progress animation, call setEnabled(false) on the view.
 * <p>
 * This layout should be made the parent of the view that will be refreshed as a
 * result of the gesture and can only support one direct child. This view will
 * also be made the target of the gesture and will be forced to match both the
 * width and the height supplied in this layout. The SwipeRefreshLayout does not
 * provide accessibility events; instead, a menu item must be provided to allow
 * refresh of the content wherever this gesture is used.
 * </p>
 */
@TargetApi(Build.VERSION_CODES.KITKAT)
public class SwipeRefreshLayout extends ViewGroup {
	// Maps to ProgressBar.Large style
	public static final int LARGE = MaterialProgressDrawable.LARGE;
	// Maps to ProgressBar default style
	public static final int DEFAULT = MaterialProgressDrawable.DEFAULT;

	private static final String LOG_TAG = SwipeRefreshLayout.class.getSimpleName();

	private static final int MAX_ALPHA = 255;
	private static final int STARTING_PROGRESS_ALPHA = (int) (.3f * MAX_ALPHA);

	private static final int CIRCLE_DIAMETER = 40;
	private static final int CIRCLE_DIAMETER_LARGE = 56;

	private static final float DECELERATE_INTERPOLATION_FACTOR = 2f;
	private static final int INVALID_POINTER = -1;
	private static final float DRAG_RATE = .5f;

	// Max amount of circle that can be filled by progress during swipe gesture,
	// where 1.0 is a full circle
	private static final float MAX_PROGRESS_ANGLE = .8f;

	private static final int SCALE_DOWN_DURATION = 150;

	private static final int ALPHA_ANIMATION_DURATION = 300;

	private static final int ANIMATE_TO_TRIGGER_DURATION = 200;

	private static final int ANIMATE_TO_START_DURATION = 200;

	// Default background for the progress spinner
	private static final int CIRCLE_BG_LIGHT = 0XFFffffff;
	// Default offset in dips from the top of the view to where the progress
	// spinner should stop
	private static final int DEFAULT_CIRCLE_TARGET = 64;

	private View mTarget; // the target of the gesture
	private OnRefreshListener mListener;
	private boolean mRefreshing = false;
	private int mTouchSlop;
	private float mTotalDragDistance = -1;
	private int mMediumAnimationDuration;
	private int mCurrentTargetOffsetTop;
	// Whether or not the starting offset has been determined.
	private boolean mOriginalOffsetCalculated = false;

	private float mInitialMotionY;
	private boolean mIsBeingDragged;
	private int mActivePointerId = INVALID_POINTER;
	// Whether this item is scaled up rather than clipped
	private boolean mScale;

	// Target is returning to its start offset because it was cancelled or a
	// refresh was triggered.
	private boolean mReturningToStart;
	private final DecelerateInterpolator mDecelerateInterpolator;
	private static final int[] LAYOUT_ATTRS = new int[] { android.R.attr.enabled };

	private CircleImageView mCircleView;
	private int mCircleViewIndex = -1;

	protected int mFrom;

	private float mStartingScale;

	protected int mOriginalOffsetTop;

	private MaterialProgressDrawable mProgress;

	private Animation mScaleAnimation;

	private Animation mScaleDownAnimation;

	private Animation mAlphaStartAnimation;

	private Animation mAlphaMaxAnimation;

	private Animation mScaleDownToStartAnimation;

	private float mSpinnerFinalOffset;

	private boolean mNotify;

	private int mCircleWidth;

	private int mCircleHeight;

	// Whether the client has set a custom starting position;
	private boolean mUsingCustomStart;

	public static boolean issetTou = true;// 传递事件 避免冲突
	public static boolean ishideview = false;// 控制view位置

	public OnRefreshHideView clickLonhideistener;
	private Animation.AnimationListener mRefreshListener = new Animation.AnimationListener() {
		@Override
		public void onAnimationStart(Animation animation) {
		}

		@Override
		public void onAnimationRepeat(Animation animation) {
		}

		@Override
		public void onAnimationEnd(Animation animation) {
			if (mRefreshing) {
				// Make sure the progress view is fully visible
				mProgress.setAlpha(MAX_ALPHA);
				mProgress.start();
				if (mNotify) {
					if (mListener != null) {
						mListener.onRefresh();
					}
				}
			} else {
				mProgress.stop();
				mCircleView.setVisibility(View.GONE);
				setColorViewAlpha(MAX_ALPHA);
				// Return the circle to its start position
				if (mScale) {
					setAnimationProgress(0 /*
											 * animation complete and view is
											 * hidden
											 */);
				} else {
					setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCurrentTargetOffsetTop, true /*
																									 * requires
																									 * update
																									 */);
				}
			}
			mCurrentTargetOffsetTop = mCircleView.getTop();
		}
	};

	private void setColorViewAlpha(int targetAlpha) {
		mCircleView.getBackground().setAlpha(targetAlpha);
		mProgress.setAlpha(targetAlpha);
	}

	/**
	 * The refresh indicator starting and resting position is always positioned
	 * near the top of the refreshing content. This position is a consistent
	 * location, but can be adjusted in either direction based on whether or not
	 * there is a toolbar or actionbar present.
	 * 
	 * @param scale
	 *            Set to true if there is no view at a higher z-order than where
	 *            the progress spinner is set to appear.
	 * @param start
	 *            The offset in pixels from the top of this view at which the
	 *            progress spinner should appear.
	 * @param end
	 *            The offset in pixels from the top of this view at which the
	 *            progress spinner should come to rest after a successful swipe
	 *            gesture.
	 */
	public void setProgressViewOffset(boolean scale, int start, int end) {
		mScale = scale;
		mCircleView.setVisibility(View.GONE);
		mOriginalOffsetTop = mCurrentTargetOffsetTop = start;
		mSpinnerFinalOffset = end;
		mUsingCustomStart = true;
		mCircleView.invalidate();
	}

	/**
	 * The refresh indicator resting position is always positioned near the top
	 * of the refreshing content. This position is a consistent location, but
	 * can be adjusted in either direction based on whether or not there is a
	 * toolbar or actionbar present.
	 * 
	 * @param scale
	 *            Set to true if there is no view at a higher z-order than where
	 *            the progress spinner is set to appear.
	 * @param end
	 *            The offset in pixels from the top of this view at which the
	 *            progress spinner should come to rest after a successful swipe
	 *            gesture.
	 */
	public void setProgressViewEndTarget(boolean scale, int end) {
		mSpinnerFinalOffset = end;
		mScale = scale;
		mCircleView.invalidate();
	}

	/**
	 * One of DEFAULT, or LARGE.
	 */
	public void setSize(int size) {
		if (size != MaterialProgressDrawable.LARGE && size != MaterialProgressDrawable.DEFAULT) {
			return;
		}
		final DisplayMetrics metrics = getResources().getDisplayMetrics();
		if (size == MaterialProgressDrawable.LARGE) {
			mCircleHeight = mCircleWidth = (int) (CIRCLE_DIAMETER_LARGE * metrics.density);
		} else {
			mCircleHeight = mCircleWidth = (int) (CIRCLE_DIAMETER * metrics.density);
		}
		// force the bounds of the progress circle inside the circle view to
		// update by setting it to null before updating its size and then
		// re-setting it
		mCircleView.setImageDrawable(null);
		mProgress.updateSizes(size);
		mCircleView.setImageDrawable(mProgress);
	}

	/**
	 * Simple constructor to use when creating a SwipeRefreshLayout from code.
	 * 
	 * @param context
	 */
	public SwipeRefreshLayout(Context context) {
		this(context, null);
	}

	/**
	 * Constructor that is called when inflating SwipeRefreshLayout from XML.
	 * 
	 * @param context
	 * @param attrs
	 */
	public SwipeRefreshLayout(Context context, AttributeSet attrs) {
		super(context, attrs);

		mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

		mMediumAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);

		setWillNotDraw(false);
		mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR);

		final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
		setEnabled(a.getBoolean(0, true));
		a.recycle();

		final DisplayMetrics metrics = getResources().getDisplayMetrics();
		mCircleWidth = (int) (CIRCLE_DIAMETER * metrics.density);
		mCircleHeight = (int) (CIRCLE_DIAMETER * metrics.density);

		createProgressView();
		ViewCompat.setChildrenDrawingOrderEnabled(this, true);
		// the absolute offset has to take into account that the circle starts
		// at an offset
		mSpinnerFinalOffset = DEFAULT_CIRCLE_TARGET * metrics.density;
		mTotalDragDistance = mSpinnerFinalOffset;
	}

	protected int getChildDrawingOrder(int childCount, int i) {
		if (mCircleViewIndex < 0) {
			return i;
		} else if (i == childCount - 1) {
			// Draw the selected child last
			return mCircleViewIndex;
		} else if (i >= mCircleViewIndex) {
			// Move the children after the selected child earlier one
			return i + 1;
		} else {
			// Keep the children before the selected child the same
			return i;
		}
	}

	private void createProgressView() {
		mCircleView = new CircleImageView(getContext(), CIRCLE_BG_LIGHT, CIRCLE_DIAMETER / 2);
		mProgress = new MaterialProgressDrawable(getContext(), this);
		mProgress.setBackgroundColor(CIRCLE_BG_LIGHT);
		mCircleView.setImageDrawable(mProgress);
		mCircleView.setVisibility(View.GONE);
		addView(mCircleView);
	}

	/**
	 * Set the listener to be notified when a refresh is triggered via the swipe
	 * gesture.
	 */
	public void setOnRefreshListener(OnRefreshListener listener) {
		mListener = listener;
	}

	/**
	 * Pre API 11, alpha is used to make the progress circle appear instead of
	 * scale.
	 */
	private boolean isAlphaUsedForScale() {
		return android.os.Build.VERSION.SDK_INT < 11;
	}

	/**
	 * Notify the widget that refresh state has changed. Do not call this when
	 * refresh is triggered by a swipe gesture.
	 * 
	 * @param refreshing
	 *            Whether or not the view should show refresh progress.
	 */
	public void setRefreshing(boolean refreshing) {
		if (refreshing && mRefreshing != refreshing) {
			// scale and show
			mRefreshing = refreshing;
			int endTarget = 0;
			if (!mUsingCustomStart) {
				endTarget = (int) (mSpinnerFinalOffset + mOriginalOffsetTop);
			} else {
				endTarget = (int) mSpinnerFinalOffset;
			}
			setTargetOffsetTopAndBottom(endTarget - mCurrentTargetOffsetTop, true /*
																				 * requires
																				 * update
																				 */);
			mNotify = false;
			startScaleUpAnimation(mRefreshListener);
		} else {
			setRefreshing(refreshing, false /* notify */);
		}
	}

	private void startScaleUpAnimation(AnimationListener listener) {
		mCircleView.setVisibility(View.VISIBLE);
		if (android.os.Build.VERSION.SDK_INT >= 11) {
			// Pre API 11, alpha is used in place of scale up to show the
			// progress circle appearing.
			// Don't adjust the alpha during appearance otherwise.
			mProgress.setAlpha(MAX_ALPHA);
		}
		mScaleAnimation = new Animation() {
			@Override
			public void applyTransformation(float interpolatedTime, Transformation t) {
				setAnimationProgress(interpolatedTime);
			}
		};
		mScaleAnimation.setDuration(mMediumAnimationDuration);
		if (listener != null) {
			mCircleView.setAnimationListener(listener);
		}
		mCircleView.clearAnimation();
		mCircleView.startAnimation(mScaleAnimation);
	}

	/**
	 * Pre API 11, this does an alpha animation.
	 * 
	 * @param progress
	 */
	private void setAnimationProgress(float progress) {
		if (isAlphaUsedForScale()) {
			setColorViewAlpha((int) (progress * MAX_ALPHA));
		} else {
			ViewCompat.setScaleX(mCircleView, progress);
			ViewCompat.setScaleY(mCircleView, progress);
		}
	}

	private void setRefreshing(boolean refreshing, final boolean notify) {
		if (mRefreshing != refreshing) {
			mNotify = notify;
			ensureTarget();
			mRefreshing = refreshing;
			if (mRefreshing) {
				animateOffsetToCorrectPosition(mCurrentTargetOffsetTop, mRefreshListener);
			} else {
				startScaleDownAnimation(mRefreshListener);
			}
		}
	}

	private void startScaleDownAnimation(Animation.AnimationListener listener) {
		mScaleDownAnimation = new Animation() {
			@Override
			public void applyTransformation(float interpolatedTime, Transformation t) {
				setAnimationProgress(1 - interpolatedTime);
			}
		};
		mScaleDownAnimation.setDuration(SCALE_DOWN_DURATION);
		mCircleView.setAnimationListener(listener);
		mCircleView.clearAnimation();
		mCircleView.startAnimation(mScaleDownAnimation);
	}

	private void startProgressAlphaStartAnimation() {
		mAlphaStartAnimation = startAlphaAnimation(mProgress.getAlpha(), STARTING_PROGRESS_ALPHA);
	}

	private void startProgressAlphaMaxAnimation() {
		mAlphaMaxAnimation = startAlphaAnimation(mProgress.getAlpha(), MAX_ALPHA);
	}

	private Animation startAlphaAnimation(final int startingAlpha, final int endingAlpha) {
		// Pre API 11, alpha is used in place of scale. Don't also use it to
		// show the trigger point.
		if (mScale && isAlphaUsedForScale()) {
			return null;
		}
		Animation alpha = new Animation() {
			@Override
			public void applyTransformation(float interpolatedTime, Transformation t) {
				mProgress.setAlpha((int) (startingAlpha + ((endingAlpha - startingAlpha) * interpolatedTime)));
			}
		};
		alpha.setDuration(ALPHA_ANIMATION_DURATION);
		// Clear out the previous animation listeners.
		mCircleView.setAnimationListener(null);
		mCircleView.clearAnimation();
		mCircleView.startAnimation(alpha);
		return alpha;
	}

	/**
	 * Set the background color of the progress spinner disc.
	 * 
	 * @param colorRes
	 *            Resource id of the color.
	 */
	public void setProgressBackgroundColor(int colorRes) {
		mCircleView.setBackgroundColor(colorRes);
		mProgress.setBackgroundColor(getResources().getColor(colorRes));
	}

	/**
	 * @deprecated Use {@link #setColorSchemeResources(int...)}
	 */
	@Deprecated
	public void setColorScheme(int... colors) {
		setColorSchemeResources(colors);
	}

	/**
	 * Set the color resources used in the progress animation from color
	 * resources. The first color will also be the color of the bar that grows
	 * in response to a user swipe gesture.
	 * 
	 * @param colorResIds
	 */
	public void setColorSchemeResources(int... colorResIds) {
		int colorIds[] = new int[] {};
		final Resources res = getResources();
		int[] colorRes = new int[colorResIds.length];
		for (int i = 0; i < colorResIds.length; i++) {
			colorRes[i] = res.getColor(colorResIds[i]);
		}
		setColorSchemeColors(colorRes);
	}

	/**
	 * Set the colors used in the progress animation. The first color will also
	 * be the color of the bar that grows in response to a user swipe gesture.
	 * 
	 * @param colors
	 */
	public void setColorSchemeColors(int... colors) {
		ensureTarget();
		mProgress.setColorSchemeColors(colors);
	}

	/**
	 * @return Whether the SwipeRefreshWidget is actively showing refresh
	 *         progress.
	 */
	public boolean isRefreshing() {
		return mRefreshing;
	}

	private void ensureTarget() {
		// Don't bother getting the parent height if the parent hasn't been laid
		// out yet.
		if (mTarget == null) {
			for (int i = 0; i < getChildCount(); i++) {
				View child = getChildAt(i);
				if (!child.equals(mCircleView)) {
					mTarget = child;
					break;
				}
			}
		}
	}

	/**
	 * Set the distance to trigger a sync in dips
	 * 
	 * @param distance
	 */
	public void setDistanceToTriggerSync(int distance) {
		mTotalDragDistance = distance;
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		final int width = getMeasuredWidth();
		final int height = getMeasuredHeight();
		if (getChildCount() == 0) {
			return;
		}
		if (mTarget == null) {
			ensureTarget();
		}
		if (mTarget == null) {
			return;
		}
		final View child = mTarget;
		final int childLeft = getPaddingLeft();
		final int childTop = getPaddingTop();
		final int childWidth = width - getPaddingLeft() - getPaddingRight();
		final int childHeight = height - getPaddingTop() - getPaddingBottom();
		child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
		int circleWidth = mCircleView.getMeasuredWidth();
		int circleHeight = mCircleView.getMeasuredHeight();
		mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop, (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight);
	}

	@Override
	public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		if (mTarget == null) {
			ensureTarget();
		}
		if (mTarget == null) {
			return;
		}
		mTarget.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
				MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
		mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mCircleHeight, MeasureSpec.EXACTLY));
		if (!mUsingCustomStart && !mOriginalOffsetCalculated) {
			mOriginalOffsetCalculated = true;
			mCurrentTargetOffsetTop = mOriginalOffsetTop = -mCircleView.getMeasuredHeight();
		}
		mCircleViewIndex = -1;
		// Get the index of the circleview.
		for (int index = 0; index < getChildCount(); index++) {
			if (getChildAt(index) == mCircleView) {
				mCircleViewIndex = index;
				break;
			}
		}
	}

	/**
	 * @return Whether it is possible for the child view of this layout to
	 *         scroll up. Override this if the child view is a custom view.
	 */
	public boolean canChildScrollUp() {
		if (android.os.Build.VERSION.SDK_INT < 14) {
			if (mTarget instanceof AbsListView) {
				final AbsListView absListView = (AbsListView) mTarget;
				return absListView.getChildCount() > 0 && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0).getTop() < absListView.getPaddingTop());
			} else {
				return mTarget.getScrollY() > 0;
			}
		} else {
			return ViewCompat.canScrollVertically(mTarget, -1);
		}
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		ensureTarget();

		final int action = MotionEventCompat.getActionMasked(ev);

		if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
			mReturningToStart = false;
		}

		if (!isEnabled() || mReturningToStart || canChildScrollUp() || mRefreshing) {
			// Fail fast if we're not in a state where a swipe is possible
			return false;
		}

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			if (issetTou == true) {
				setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop(), true);
				mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
				mIsBeingDragged = false;
				final float initialMotionY = getMotionEventY(ev, mActivePointerId);
				if (initialMotionY == -1) {
					return false;
				}
				mInitialMotionY = initialMotionY;
			} else {
				return false;
			}

		case MotionEvent.ACTION_MOVE:
			if (issetTou == true) {
				if (mActivePointerId == INVALID_POINTER) {
					Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
					return false;
				}

				final float y = getMotionEventY(ev, mActivePointerId);
				if (y == -1) {
					return false;
				}
				final float yDiff = y - mInitialMotionY;
				if (yDiff > mTouchSlop && !mIsBeingDragged) {
					mIsBeingDragged = true;
					mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
				}
				break;
			} else {
				return false;
			}
		case MotionEventCompat.ACTION_POINTER_UP:
			onSecondaryPointerUp(ev);
			break;

		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			mIsBeingDragged = false;
			mActivePointerId = INVALID_POINTER;
			break;
		}

		return mIsBeingDragged;
	}

	private float getMotionEventY(MotionEvent ev, int activePointerId) {
		final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
		if (index < 0) {
			return -1;
		}
		return MotionEventCompat.getY(ev, index);
	}

	@Override
	public void requestDisallowInterceptTouchEvent(boolean b) {
		// Nope.
	}

	private boolean isAnimationRunning(Animation animation) {
		return animation != null && animation.hasStarted() && !animation.hasEnded();
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		final int action = MotionEventCompat.getActionMasked(ev);

		if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
			mReturningToStart = false;
		}

		if (!isEnabled() || mReturningToStart || canChildScrollUp()) {
			// Fail fast if we're not in a state where a swipe is possible
			return false;
		}

		switch (action) {
		case MotionEvent.ACTION_DOWN:
			if (issetTou == true) {
				LogUtil.defLog("------------MotionEvent.ACTION_DOWN");
				mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
				mIsBeingDragged = false;
				break;
			} else {
				return false;
			}

		case MotionEvent.ACTION_MOVE: {
			if (issetTou == true) {
				final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
				if (pointerIndex < 0) {
					Log.e(LOG_TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
					return false;
				}

				final float y = MotionEventCompat.getY(ev, pointerIndex);
				final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
				if (mIsBeingDragged) {
//					if (ishideview == false) {
//						if (clickLonhideistener != null) {
//							ishideview = true;
//							clickLonhideistener.onRefreshhideview();
//						}
//					}
					mProgress.showArrow(true);
					float originalDragPercent = overscrollTop / mTotalDragDistance;
					if (originalDragPercent < 0) {
						return false;
					}
					float dragPercent = Math.min(1f, Math.abs(originalDragPercent));
					float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3;
					float extraOS = Math.abs(overscrollTop) - mTotalDragDistance;
					float slingshotDist = mUsingCustomStart ? mSpinnerFinalOffset - mOriginalOffsetTop : mSpinnerFinalOffset;
					float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2) / slingshotDist);
					float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;
					float extraMove = (slingshotDist) * tensionPercent * 2;

					int targetY = mOriginalOffsetTop + (int) ((slingshotDist * dragPercent) + extraMove);
					// where 1.0f is a full circle
					if (mCircleView.getVisibility() != View.VISIBLE) {
						mCircleView.setVisibility(View.VISIBLE);
					}
					if (!mScale) {
						ViewCompat.setScaleX(mCircleView, 1f);
						ViewCompat.setScaleY(mCircleView, 1f);
					}
					if (overscrollTop < mTotalDragDistance) {
						if (mScale) {
							setAnimationProgress(overscrollTop / mTotalDragDistance);
						}
						if (mProgress.getAlpha() > STARTING_PROGRESS_ALPHA && !isAnimationRunning(mAlphaStartAnimation)) {
							// Animate the alpha
							startProgressAlphaStartAnimation();
						}
						float strokeStart = (float) (adjustedPercent * .8f);
						mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart));
						mProgress.setArrowScale(Math.min(1f, adjustedPercent));
					} else {
						if (mProgress.getAlpha() < MAX_ALPHA && !isAnimationRunning(mAlphaMaxAnimation)) {
							// Animate the alpha
							startProgressAlphaMaxAnimation();
						}
					}
					float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f;
					mProgress.setProgressRotation(rotation);
					setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop, true /*
																						 * requires
																						 * update
																						 */);
				}
				break;
			} else {
				return false;
			}
		}
		case MotionEventCompat.ACTION_POINTER_DOWN: {
			LogUtil.defLog("------------MotionEvent.ACTION_POINTER_DOWN");
			final int index = MotionEventCompat.getActionIndex(ev);
			mActivePointerId = MotionEventCompat.getPointerId(ev, index);
			break;
		}

		case MotionEventCompat.ACTION_POINTER_UP:
			LogUtil.defLog("------------MotionEvent.ACTION_POINTER_UP");
			onSecondaryPointerUp(ev);
			break;

		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL: {
			LogUtil.defLog("------------MotionEvent.ACTION_CANCEL");
			if (mActivePointerId == INVALID_POINTER) {
				if (action == MotionEvent.ACTION_UP) {
					Log.e(LOG_TAG, "Got ACTION_UP event but don't have an active pointer id.");
				}
				return false;
			}
			final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
			final float y = MotionEventCompat.getY(ev, pointerIndex);
			final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
			mIsBeingDragged = false;
			if (overscrollTop > mTotalDragDistance) {
				setRefreshing(true, true /* notify */);
			} else {
				// cancel refresh
				mRefreshing = false;
				mProgress.setStartEndTrim(0f, 0f);
				Animation.AnimationListener listener = null;
				if (!mScale) {
					listener = new Animation.AnimationListener() {

						@Override
						public void onAnimationStart(Animation animation) {
						}

						@Override
						public void onAnimationEnd(Animation animation) {
							if (!mScale) {
								startScaleDownAnimation(null);
							}
						}

						@Override
						public void onAnimationRepeat(Animation animation) {
						}

					};
				}
				animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener);
				mProgress.showArrow(false);
			}
			mActivePointerId = INVALID_POINTER;
			return false;
		}
		}

		return true;
	}

	private void animateOffsetToCorrectPosition(int from, AnimationListener listener) {
		mFrom = from;
		mAnimateToCorrectPosition.reset();
		mAnimateToCorrectPosition.setDuration(ANIMATE_TO_TRIGGER_DURATION);
		mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator);
		if (listener != null) {
			mCircleView.setAnimationListener(listener);
		}
		mCircleView.clearAnimation();
		mCircleView.startAnimation(mAnimateToCorrectPosition);
	}

	private void animateOffsetToStartPosition(int from, AnimationListener listener) {
		if (mScale) {
			// Scale the item back down
			startScaleDownReturnToStartAnimation(from, listener);
		} else {
			mFrom = from;
			mAnimateToStartPosition.reset();
			mAnimateToStartPosition.setDuration(ANIMATE_TO_START_DURATION);
			mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);
			if (listener != null) {
				mCircleView.setAnimationListener(listener);
			}
			mCircleView.clearAnimation();
			mCircleView.startAnimation(mAnimateToStartPosition);
		}
	}

	private final Animation mAnimateToCorrectPosition = new Animation() {
		@Override
		public void applyTransformation(float interpolatedTime, Transformation t) {
			int targetTop = 0;
			int endTarget = 0;
			if (!mUsingCustomStart) {
				endTarget = (int) (mSpinnerFinalOffset - Math.abs(mOriginalOffsetTop));
			} else {
				endTarget = (int) mSpinnerFinalOffset;
			}
			targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
			int offset = targetTop - mCircleView.getTop();
			setTargetOffsetTopAndBottom(offset, false /* requires update */);
		}
	};

	private void moveToStart(float interpolatedTime) {
		int targetTop = 0;
		targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
		int offset = targetTop - mCircleView.getTop();
		setTargetOffsetTopAndBottom(offset, false /* requires update */);
	}

	private final Animation mAnimateToStartPosition = new Animation() {
		@Override
		public void applyTransformation(float interpolatedTime, Transformation t) {
			moveToStart(interpolatedTime);
		}
	};

	private void startScaleDownReturnToStartAnimation(int from, Animation.AnimationListener listener) {
		mFrom = from;
		if (isAlphaUsedForScale()) {
			mStartingScale = mProgress.getAlpha();
		} else {
			mStartingScale = ViewCompat.getScaleX(mCircleView);
		}
		mScaleDownToStartAnimation = new Animation() {
			@Override
			public void applyTransformation(float interpolatedTime, Transformation t) {
				float targetScale = (mStartingScale + (-mStartingScale * interpolatedTime));
				setAnimationProgress(targetScale);
				moveToStart(interpolatedTime);
			}
		};
		mScaleDownToStartAnimation.setDuration(SCALE_DOWN_DURATION);
		if (listener != null) {
			mCircleView.setAnimationListener(listener);
		}
		mCircleView.clearAnimation();
		mCircleView.startAnimation(mScaleDownToStartAnimation);
	}

	private void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
		mCircleView.bringToFront();
		mCircleView.offsetTopAndBottom(offset);
		mCurrentTargetOffsetTop = mCircleView.getTop();
		if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
			invalidate();
		}
	}

	private void onSecondaryPointerUp(MotionEvent ev) {
		final int pointerIndex = MotionEventCompat.getActionIndex(ev);
		final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
		if (pointerId == mActivePointerId) {
			// This was our active pointer going up. Choose a new
			// active pointer and adjust accordingly.
			final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
			mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
		}
	}

	/**
	 * Classes that wish to be notified when the swipe gesture correctly
	 * triggers a refresh should implement this interface.
	 */
	public interface OnRefreshListener {
		public void onRefresh();
	}

	public interface OnRefreshHideView {
		public void onRefreshhideview();
	}

	public void setOnHideListener(OnRefreshHideView clickListener) {
		this.clickLonhideistener = clickListener;
	}
}